﻿/**
* CRL
*/
using CRL.Core.Extension;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace CRL.Core.Remoting
{
    public enum ServerType
    {
        ApiGenerate,
        DynamicWebApi
    }
    public abstract class AbsServer : IDisposable
    {
        public abstract ServerType ServerType { get; }
        ServerCreater __ServerCreater;
        internal string __DefaultApiPrefix = "DynamicApi";
        internal void SetServerCreater(ServerCreater serverCreater)
        {
            __ServerCreater = serverCreater;
        }
        /// <summary>
        /// 设置默认前辍
        /// </summary>
        /// <param name="prefix"></param>
        public void SetDefaultApiPrefix(string prefix)
        {
            __DefaultApiPrefix = prefix;
        }
        /// <summary>
        /// 设置jwt认证方法
        /// </summary>
        /// <param name="tokenCheck"></param>
        /// <returns></returns>
        public AbsServer UseCustomTokenCheck(TokenCheckHandler tokenCheck)
        {
            _tokenCheck = tokenCheck;
            return this;
        }
        //internal ServerCreater ServerCreater;

        public virtual void Start()
        {

        }
        public virtual void Dispose()
        {

        }
        public abstract object InvokeResult(object rq, Func<Type, object> objectCtor = null);
        protected class ErrorInfo
        {
            public string msg;
            public string code;
            public ErrorInfo(string m,string c)
            {
                msg = m;
                code = c;
            }
        }
        protected ErrorInfo InvokeMessage(MessageBase request, out object result, out Dictionary<int, object> outs, Func<Type, object> objectCtor = null)
        {
            result = null;
            outs = new Dictionary<int, object>();
            var serviceKey = $"{ServerType}.{request.ApiPrefix}.{request.Service}";
            var a = __ServerCreater.CheckServerExists(serviceKey, out serviceInfo serviceInfo);
            if (!a)
            {
                return new ErrorInfo("未找到该服务:" + serviceKey, "404");
            }
            var serviceType = serviceInfo.ServiceType;
            var constructor = serviceType.GetConstructors().Last();
            var cArgs = new List<object>();
            AbsService service;
            if (objectCtor != null)
            {
                var instanceType = serviceInfo.InterfaceType ?? serviceInfo.ServiceType;
                service = objectCtor(instanceType) as AbsService;
                if (service == null)
                {
                    return new ErrorInfo("未找到注入类型" + instanceType, "500");
                }
            }
            else
            {
                service = serviceInfo.InstaceCtor() as AbsService;
            }
            var methodInfo = serviceInfo.GetMethod(request.Method);
            if (methodInfo == null)
            {
                return new ErrorInfo("未找到该方法" + request.Method, "404");
            }
            var checkToken = true;
            var allowAnonymous = serviceInfo.GetAttribute<AllowAnonymousAttribute>();
            var allowAnonymous2 = methodInfo.GetAttribute<AllowAnonymousAttribute>();
            if (allowAnonymous != null || allowAnonymous2 != null)
            {
                checkToken = false;
            }
            //if (_tokenCheck != null)
            //{
            //    checkToken = true;
            //}
            var paramters = request.Args;
            var method = methodInfo.MethodInfo;
            var methodParamters = methodInfo.Parameters;
            outs = new Dictionary<int, object>();
            int i = 0;
            foreach (var p in methodParamters)
            {
                var value = paramters[i];

                if (p.Attributes == ParameterAttributes.Out)
                {
                    outs.Add(i, null);
                }
                else
                {
                    if (value != null)
                    {
                        if (value.GetType() != p.ParameterType)
                        {
                            var value2 = value.ToJson().ToObject(p.ParameterType);
                            paramters[i] = value2;
                        }
                    }
                    else
                    {
                        paramters[i] = value;
                    }
                }
                i += 1;
            }
            //if (request.httpPostedFile != null)
            //{
            //    service.SetPostFile(request.httpPostedFile);
            //}

            if (request.Args.Count != methodParamters.Count())
            {
                return new ErrorInfo("参数计数不正确" + request.ToJson(), "500");
            }

            if (checkToken)
            {
                if (string.IsNullOrEmpty(request.Token))
                {
                    return new ErrorInfo("请求token为空,请先登录", "401");
                    //throw new Exception("token为空");
                }
                if (_tokenCheck != null)
                {
                    string error;
                    if (!_tokenCheck(request, out var userData, out error))
                    {
                        return new ErrorInfo($"自定义认证失败:{error}", "401");
                    }
                    service.__SetAuthData(userData);
                }
            }

            var args3 = paramters?.ToArray();
            //result = method.Invoke(service, args3);
            result = methodInfo.MethodInvoker(service, args3);
            //总是返回同步结果
            if (methodInfo.IsAsync)
            {
                var task = methodInfo.TaskCreater.Invoke();
                result = task.GetResult(result as Task);

            }
            foreach (var kv in new Dictionary<int, object>(outs))
            {
                var value = args3[kv.Key];
                outs[kv.Key] = value;
            }
            return null;
        }
        internal TokenCheckHandler _tokenCheck;
    }
}
